<!--
  * @Author: ws
  * @Date: 2024-01-11 15:48:12
  * @email: 458658538@qq.com
  * @LastEditors: ws
  * @LastEditTime: 2024-01-12 14:40:54
  * @Description:
-->
<!-- @format -->

<template>
  <div class="common-tree flex h-full flex-col overflow-hidden" v-bind="$attrs" v-on="$listeners">
    <div class="p-[16px]">
      <el-input
        v-model="filterText"
        class="h-[32px] text-[14px]"
        size="small"
        placeholder="请输入关键字进行过滤"
        clearable
        suffix-icon="el-icon-search"
      />
    </div>

    <el-tree
      :key="refreshKey"
      ref="treeRef"
      class="overflow-y-auto overflow-x-hidden"
      highlight-current
      node-key="id"
      v-bind="$attrs"
      :data="treeData"
      :props="defaultProps"
      :expand-on-click-node="false"
      default-expand-all
      :allow-drag="allowDrag"
      :allow-drop="allowDrop"
      draggable
      :filter-node-method="filterNode"
      @current-change="currentChange"
      v-on="$listeners"
      @node-drop="handleDrop"
    >
      <div
        slot-scope="{ node, data }"
        class="custom-tree-node h-[32px] pr-[24px] text-[14px] leading-[32px]"
        style="width: calc(100% - 32px)"
        @mouseenter="showMoreAction(data, true)"
        @mouseleave="showMoreAction(data, false)"
      >
        <div class="c-t-label">
          <div v-popper="{ content: node.label }" class="ellipsis">{{ node.label }}</div>
        </div>

        <!-- v-show="!data.showMoreAction" -->
        <div v-show="c_Props.showMore && data.showMoreAction" class="c-t-btns absolute right-0 top-[0px] pr-[8px]">
          <el-dropdown>
            <i class="el-icon-more rotate-90"></i>
            <template slot="dropdown">
              <el-dropdown-menu class="common-tree-dropdown">
                <!-- v-if="showFunc(node, data, 'add')" -->
                <el-dropdown-item v-if="showFunc(node, data, 'add')" @click.native="() => addTreeNode(node, data)"
                  >新增</el-dropdown-item
                >
                <el-dropdown-item v-if="showFunc(node, data, 'edit')" @click.native="() => editTreeNode(node, data)">
                  编辑</el-dropdown-item
                >
                <el-dropdown-item v-if="showFunc(node, data, 'remove')" @click.native="() => delTreeNode(node, data)">
                  <span class="text-[#C41C24]">删除</span>
                </el-dropdown-item>
              </el-dropdown-menu>
            </template>
          </el-dropdown>
        </div>
      </div>
    </el-tree>
    <el-button v-show="c_Props.showAddFirst" icon="CirclePlus" @click="addTreeNode">新增一级菜单</el-button>

    <!-- 新增、编辑文件夹 -->
    <el-dialog title="提示" :visible.sync="dialogVisible" width="400px">
      <el-form
        ref="dialogForm"
        :model="dialogForm"
        size="small"
        label-position="top"
        :rules="{}"
        :validate-on-rule-change="false"
      >
        <el-form-item
          label="菜单名称："
          prop="name"
          :rules="[{ required: true, message: '请输入菜单名称', trigger: 'blur' }]"
        >
          <el-input
            v-model="dialogForm.name"
            placeholder="请输入菜单名称"
            :maxlength="20"
            :show-word-limit="true"
            class="w-full"
          ></el-input>
        </el-form-item>
      </el-form>
      <span slot="footer" class="dialog-footer">
        <el-button size="small" @click="dialogVisible = false">取 消</el-button>
        <el-button type="primary" size="small" @click="onFileSave">确 定</el-button>
      </span>
    </el-dialog>
  </div>
</template>

<script>
import { toArrayTree } from "xe-utils";
import {
  reportMenuAdd,
  reportMenuDelete,
  reportMenuList,
  reportMenuUpdate,
  reportMenuUpdateSort,
} from "@/api/report-menu";

export default {
  name: "CommonTree",
  props: {
    option: {
      type: Object,
    },
    canDeleteCallBack: {
      type: Function,
    },
    defalutKey: { type: Number },
  },
  data() {
    return {
      filterText: "",
      defaultProps: {
        children: "children",
        label: "name",
      },
      treeData: [],
      refreshKey: [],
      // 新增、编辑文件夹
      dialogVisible: false,
      dialogForm: {
        name: "",
        id: null,
        parentId: null,
      },
      currentNodeKey: "",
      arrayData: [],
    };
  },
  computed: {
    c_Props() {
      //隐藏操作按钮
      const showMore = true;
      const showAdd = true;
      const showEdit = true;
      const showRemove = true;
      const showAddFirst = false;
      const type = -1;
      return {
        showAdd,
        showEdit,
        showRemove,
        showAddFirst,
        type,
        showMore,
        ...this.option,
      };
    },
  },
  watch: {
    filterText: {
      immediate: true,
      handler(newValue) {
        this.$refs.treeRef?.filter(newValue);
      },
    },
    defalutKey: {
      immediate: true,
      handler(newValue) {
        this.currentNodeKey = newValue;
      },
    },
  },
  mounted() {
    // this.init();
  },
  activated() {
    this.init();
    // debugger;
  },
  methods: {
    filterNode(value, data) {
      if (!value) return true;
      return data.name.includes(value);
    },
    //#region 拖拽处理
    //@author: ws
    //@date: 2024-01-05 14:34:01

    /**允许拖拽
     *
     * @param draggingNode
     */
    allowDrag(draggingNode) {
      return true;
    },

    /**允许着落
     *
     * @param draggingNode
     */
    allowDrop(draggingNode, dropNode, type) {
      return draggingNode.parent == dropNode.parent && ["prev", "next"].includes(type);
    },

    handleDrop(draggingNode, dropNode, dropType, ev) {
      const { treeData, query } = this;
      let ids = [];
      if (dropNode.parent) {
        ids = dropNode.parent.childNodes.map((n) => n.data.id);
      }
      reportMenuUpdateSort(ids)
        .then((res) => {
          this.$message.success("修改成功");
        })
        .finally(() => {
          query();
        });
    },

    //#endregion

    //#region 编辑处理
    //@author: ws
    //@date: 2024-01-05 14:36:12
    addTreeNode(node, row) {
      const that = this;
      if (!node) {
        node = { level: 1 };
      }
      this.dialogForm.name = "";
      this.dialogForm.id = null;
      this.dialogForm.parentId = row?.id ?? null;
      this.dialogVisible = true;
      this.$nextTick(function () {
        that.$refs["dialogForm"].clearValidate();
      });
    },
    editTreeNode(node, row) {
      const that = this;
      this.dialogForm.name = row.name;
      this.dialogForm.id = row.id;
      this.dialogForm.parentId = row.parentId;
      this.dialogVisible = true;
      this.$nextTick(function () {
        that.$refs["dialogForm"].clearValidate();
      });
    },
    onFileSave() {
      const { name, id, parentId } = { ...this.dialogForm };
      this.$refs.dialogForm.validate(async (valid) => {
        if (valid) {
          const data = id ? await reportMenuUpdate({ id, name }) : await reportMenuAdd({ parentId, name });
          if (data) {
            this.dialogVisible = false;
            this.$message.success(id ? "修改成功" : "新增成功");
            this.query();
          }
        }
      });
    },
    async delTreeNode(node, row) {
      const params = {
        id: node.data?.id,
      };
      this.$confirm("此操作将永久删除该目录, 是否继续?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          reportMenuDelete(params).then((res) => {
            this.$message({
              type: "success",
              message: "删除成功!",
            });
            this.query();
          });
        })
        .catch(() => {
          this.$message({
            type: "warning",
            message: "已取消删除",
          });
        });
    },
    //#endregion

    async query() {
      const { type } = this.c_Props;
      return reportMenuList({
        type,
      }).then((res) => {
        this.arrayData = res;
        // res.forEach((f) => (f.showMoreAction = false));
        this.treeData = toArrayTree(res, {
          parentKey: "parentId",
          // sortKey: {
          //   field: "sort",
          // },
        });
        this.refreshKey++;
      });
    },

    async init() {
      await this.query();
      const { treeData } = this;
      if (Array.isArray(treeData) && treeData.length > 0) {
        if (this.$refs.treeRef) {
          let { arrayData, currentNodeKey } = this;
          if (!arrayData.some((s) => s.id == currentNodeKey)) {
            currentNodeKey = treeData[0]?.id;
            this.currentNodeKey = currentNodeKey;
          }
          this.$refs.treeRef.setCurrentNode({
            id: currentNodeKey,
          });
          // let node = this.$refs.treeRef.getCurrentNode();
          // this.$refs.treeRef.setCurrentKey(treeData[0]?.id);
          const node = this.$refs.treeRef.getNode(currentNodeKey);
          this.$emit("manualCurrentChange", node.data, node);
        }
      }
    },

    showFunc(node, data, funcType) {
      const { showAdd, showEdit, showRemove } = this.c_Props;
      const { level } = node;
      switch (funcType) {
        case "add":
          return showAdd && level < 3;
        case "edit":
          return showEdit && level > 1;
        case "remove":
          return showRemove && level > 1 && level < 4;
        default:
          return false;
      }
    },

    showMoreAction(data, show) {
      this.$set(data, "showMoreAction", show);
      // data.showMoreAction = show;
    },

    currentChange(data) {
      this.currentNodeKey = data.id;
    },
  },
};
</script>

<style lang="scss" scoped>
.common-tree {
  .el-tree {
    flex: 1;
    background: transparent;

    ::v-deep .el-tree-node__content {
      position: relative;
      height: 32px;

      .el-tree-node__expand-icon {
        padding: 8px;
      }
    }
  }
}

::v-deep .is-leaf + .custom-tree-node {
  padding-left: 4px;
}

.el-dropdown-menu {
  border: 1px solid #e8eaef;
  box-shadow: 0 1px 4px 0 rgb(0 0 0 / 0.05);
}
</style>

<style lang="scss">
.common-tree-dropdown {
  .el-dropdown-menu__item {
    height: 32px;
    padding: 0 8px !important;
    font-size: 14px;
    line-height: 32px !important;
  }
}
</style>
